﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace NuMvvm.Validation
{
    public static class Validator
    {
        public static bool TryValidateObject(object objectInstance, ICollection<ValidationResult> results)
        {
            Contract.Requires(objectInstance != null);
            Contract.Requires(results != null);

            bool result = true;

            var type = objectInstance.GetType();
            foreach(var propertyInfo in type.GetRuntimeProperties())
            {
                var validationContext = new ValidationContext(objectInstance) {  MemberName = propertyInfo.Name };
                result = result && TryValidateProperty(objectInstance, validationContext, results);
            }

            return result;
        }

        public static bool TryValidateProperty(object value, ValidationContext validationContext, ICollection<ValidationResult> results)
        {
            Contract.Requires(validationContext != null);
            Contract.Requires(results != null);

            PropertyInfo propertyInfo = null;
            var type = validationContext.ObjectInstance.GetType();
        
            propertyInfo = type
                .GetRuntimeProperties()
                .First(x => x.Name == validationContext.MemberName);

            var attributes = propertyInfo.GetCustomAttributes(typeof(ValidationAttribute), true)
                .Cast<ValidationAttribute>();

            bool result = true;

            foreach (var attribute in attributes)
            {
                try
                {
                    attribute.Validate(value, validationContext);            
                }
                catch (ValidationException validationException)
                {
                    var validationResult = validationException.ValidationResult;
                    if (validationResult != null)
                    {
                        results.Add(validationResult);
                    }
                    result = result && (validationResult == null);
                }
            }
            return result;
        }
    }
}
